package com.bondqin.demo.convert;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Page;
import org.springframework.util.Assert;

public abstract class MyConverter<E, V> implements Converter<E, V> {
	
	protected Class<V> voType;
	
	protected Class<E> entityType;
	
	protected MyConverter(Class<V> voType, Class<E> entityType) {
		Assert.notNull(voType);
		Assert.notNull(entityType);
		
		this.voType = voType;
		this.entityType = entityType;
	}

	public E convertToEntity(V vo) {
		Assert.notNull(vo);
		
		E entity = BeanUtils.instantiate(entityType);
		
		BeanUtils.copyProperties(vo, entity);
		
		afterSimpleConvertToEntity(vo, entity);
		
		return entity;
	}
	
	abstract void afterSimpleConvertToEntity(V vo, E entity);
	
	public V convertToVo(E entity) {
		Assert.notNull(entity);
		
		V vo = BeanUtils.instantiate(voType);
		BeanUtils.copyProperties(entity, vo);
		
		afterSimpleConvertToVo(entity, vo);
		
		return vo;
	}
	
	abstract void afterSimpleConvertToVo(E entity, V vo);

	@Override
	public V convert(E entity) {
		Assert.notNull(entity);
		
		return convertToVo(entity);
	};

	public List<V> convertList(List<E> entityList) {
		Assert.notNull(entityList);
		
		List<V> voList = new ArrayList<V>();
		
		for(E entity : entityList) {
			V vo = convert(entity);
			voList.add(vo);
		}

		return voList;
	}
	
	public Page<V> convertPage(Page<E> entityPage) {
		Assert.notNull(entityPage);
		
		Page<V> voPage = entityPage.map(this);
		
		return voPage;
	}
	
	public static <T> T simpleConvert(Object source, Class<T> targetType) {
		Assert.notNull(source);
		Assert.notNull(targetType);
		
		T target = null;
		try {
			target = targetType.newInstance();
			BeanUtils.copyProperties(target, source);
		} catch (Exception e) {
		}
		return target;
	}

	public static <T> List<T> simpleConvert(List<Object> sourceList, Class<T> targetType) {
		Assert.notNull(sourceList);
		Assert.notNull(targetType);
		
		List<T> targetList = new ArrayList<T>();
		
		for(Object source : sourceList) {
			T target = simpleConvert(source, targetType);
			targetList.add(target);
		}
		return targetList;
	}
	
	public static <S, T> Page<T> simpleConvert(Page<S> sourcePage, Class<T> targetType) {
		Assert.notNull(sourcePage);
		Assert.notNull(targetType);
		
		Page<T> targetPage = sourcePage.map(new Converter<S, T>() {
			@Override
			public T convert(S source) {
				T target = MyConverter.simpleConvert(source, targetType);
				return target;
			}
		});
		return targetPage;
	}

}